# -*- coding: utf-8 -*-
"""
Created on Fri Apr  9 16:27:54 2021

@author: Apple
"""

import numpy as np
import pandas as pd
import math
import matplotlib.pyplot as plt

def read_data():
    Y = []
    X = []
    data = pd.read_csv('testdata.csv') # 读取数据
    Data = data.iloc[:,:].values.tolist() # 转换为列表形式
    for i in range(len(Data)):
        x = Data[i][0]
        y = Data[i][1]
        X.append(x)
        Y.append(y)
    return X,Y


def function(i): # 设置函数解析式
    if i == 0:
        f = lambda x:1
        return f
    if i ==1:
        f = lambda x:x
        return f
    if i ==2:
        f = lambda x:pow(x,2)
        return f
    if i == 3:
        f = lambda x:pow(x,3)
        return f

def markA(i,j,X:list,m): # 记号（h,g）
    h = function(i)
    g = function(j)
    sumf = 0
    for i in range(m):
        sumf += round(h(X[i]),2)*round(g(X[i]),2)
    return sumf

def markB(i,X:list,Y:list,m): # 记号（h,y）
    h = function(i)
    sumf = 0
    for i in range(m):
        sumf += round(h(X[i]),2)*round(Y[i],2)
    return sumf

def SEcal(r:list): # 求解平方误差
    SE = 0
    for i in range(len(r)):        
        SE+=math.pow(r[i],2)
    return SE
        
def functioncal(x:list,X:list): # 求解拟合值
    y = []
    for i in range(len(X)):
        value = 0
        for j in range(len(x)):            
            f = function(j)
            value += round(x[j][0]*f(X[i]),3)
        y.append(value)
    return y
    
def main():
    
    X = [] #节点
    Y = [] # 节点对应的函数值
    a = 4 # 拟合函数个数
    
    X,Y = read_data()
    
    A = np.zeros((a,a)) # Ax=B
    for i in range(a):
        for j in range(a):
            A[i][j] = markA(i,j,X,len(X))
    
    B = np.zeros((a,1))
    for i in range(a):
        B[i][0] = markB(i,X,Y,len(X))
        
    # print(X)
    # print(Y)
    # print(A)
    # print(B)
    
    x = np.linalg.solve(A,B) # 求解x
    print('c1=',format(x[0][0],".3f"))
    print('c2=',format(x[1][0],".3f"))
    print('c3=',format(x[2][0],".3f"))
    print('c4=',format(x[3][0],".3f"))
    print('\n')
    y = functioncal(x,X)
        
    r = [] # 存储误差
    for i in range(len(Y)):
        r.append(Y[i]-y[i])
        
    SE = SEcal(r) # 平方误差
    e2 = math.sqrt(SE) # 2范数误差
    RMSE = math.sqrt(SE/len(r)) # 平均平方根误差
    
    print('平方误差为：',format(SE,".3f"))
    print('2范数误差为：',format(e2,".3f"))
    print('平均平方根误差为：',format(RMSE,".3f"))


    plt.figure(figsize=(8,6),dpi=300) # 设置图片大小
    plt.rcParams['font.sans-serif']=['SimHei']
    
    plt.scatter(X,Y,s=np.pi * 2**2,c='#00CED1',label='原始数据') # 绘制散点图
    
    plt.plot(X,y,color='red',linestyle='-',linewidth=1,label='拟合曲线') # 绘制折线图
    
    plt.legend(loc='upper left') # 图例位置位于左上方
    plt.legend(loc='best')
    plt.xlabel('x') # 设置坐标标题
    plt.ylabel('y')
    
    # title = ''
    # a_str = []
    # b_str = ['']
    # c_str = ['']

    # for i in range(a):
    #     a_str.append(format(x[i][0],".3f"))
    
    # for i in range(a-1):
    #     b_str.append(f'x^{i+1}')
    #     c_str.append('+')
    
    # for i in range(a-1,-1,-1):
    #     title += a_str[i]+b_str[i]+c_str[i]

    # plt.title('拟合函数:'+title)
    
    plt.savefig('test.jpg',dpi=300) # 保存图片

if __name__ == "__main__":
    main()
